#include "nemu.h"
#include <stdlib.h>
#include <time.h>

CPU_state cpu;
SegDescriptor *seg_descriptor;

const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};

void reg_test() {
	srand(time(0));
	uint32_t sample[8];
	uint32_t eip_sample = rand();
	cpu.eip = eip_sample;

	int i;
	for(i = R_EAX; i <= R_EDI; i ++) {
		sample[i] = rand();
		reg_l(i) = sample[i];
		assert(reg_w(i) == (sample[i] & 0xffff));
	}

	assert(reg_b(R_AL) == (sample[R_EAX] & 0xff));
	assert(reg_b(R_AH) == ((sample[R_EAX] >> 8) & 0xff));
	assert(reg_b(R_BL) == (sample[R_EBX] & 0xff));
	assert(reg_b(R_BH) == ((sample[R_EBX] >> 8) & 0xff));
	assert(reg_b(R_CL) == (sample[R_ECX] & 0xff));
	assert(reg_b(R_CH) == ((sample[R_ECX] >> 8) & 0xff));
	assert(reg_b(R_DL) == (sample[R_EDX] & 0xff));
	assert(reg_b(R_DH) == ((sample[R_EDX] >> 8) & 0xff));

	assert(sample[R_EAX] == cpu.eax);
	assert(sample[R_ECX] == cpu.ecx);
	assert(sample[R_EDX] == cpu.edx);
	assert(sample[R_EBX] == cpu.ebx);
	assert(sample[R_ESP] == cpu.esp);
	assert(sample[R_EBP] == cpu.ebp);
	assert(sample[R_ESI] == cpu.esi);
	assert(sample[R_EDI] == cpu.edi);

	assert(eip_sample == cpu.eip);
}

void list_reg() {
	int i;
	for(i = R_EAX; i <= R_EDI; i ++) {
		printf("%s\t0x%08x\t%d\n", regsl[i], reg_l(i), reg_l(i));
	}
	printf("eip\t0x%08x\t%d\n", cpu.eip, cpu.eip);
}

uint32_t get_reg_val(char* reg, bool* success) {
	if(strcmp(reg, "eip") == 0) {
		*success = true;
		return cpu.eip;
	}
	int i;
	for(i = R_EAX; i <= R_EDI; i ++) {
		if(strcmp(reg, regsl[i]) == 0) {
			*success = true;
			return reg_l(i);
		}
		if(strcmp(reg, regsw[i]) == 0) {
			*success = true;
			return reg_w(i);
		}
		if(strcmp(reg, regsb[i]) == 0) {
			*success = true;
			return reg_b(i);
		}
	}
	*success = false;
	return 0;
}

void load_sreg_cache(uint8_t sreg) {
	uint16_t index = cpu.sreg[sreg].selector >> 3;
	Assert((index << 3) < cpu.gdtr.limit, "segment selector out of limit");

	lnaddr_t descriptor_addr = cpu.gdtr.base + (index << 3);
	SegDescriptor seg_descriptor;
	seg_descriptor.first_part = lnaddr_read(descriptor_addr, 4);
	seg_descriptor.second_part = lnaddr_read(descriptor_addr + 4, 4);
	Assert(seg_descriptor.p == 1, "segment not present");

	cpu.sreg[sreg].base = (seg_descriptor.base_1) | (seg_descriptor.base_2 << 16) | (seg_descriptor.base_3 << 24);
	cpu.sreg[sreg].limit = (seg_descriptor.limit_1) | (seg_descriptor.limit_2 << 16) | (0xfff << 24);
}